﻿// <copyright file="PropertyComparer.cs" company="SingularityShift">
// Copyright (c) 2009 SingularityShift.com
// </copyright>
// <author>Ben McClure</author>
// <email>ben@singularityshift.com</email>
// <date>2009-08-14</date>
// <summary>An IComparer designed to compare an IMod by one of its properties</summary>
namespace GameLib.Games.Components
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Text;

    /// <summary>
    /// Compares an IMod by any of its properties
    /// </summary>
    /// <typeparam name="T">The type of IMod object this comparer compares</typeparam>
    public class ModPropertyComparer<T> : IComparer<T> where T : IMod
    {
        /// <summary>
        /// Stores the IComparer instance
        /// </summary>
        private readonly IComparer comparer;
        
        /// <summary>
        /// Stores the PropertyDescriptor for the property to compare
        /// </summary>
        private PropertyDescriptor propertyDescriptor;
        
        /// <summary>
        /// Indicates whether to sort in reverse
        /// </summary>
        private int reverse;

        /// <summary>
        /// Initializes a new instance of the PropertyComparer class, specifying a property descriptor and sort direction
        /// </summary>
        /// <param name="property">A PropertyDescriptor describing the property to sort by</param>
        /// <param name="direction">The sort direction to sort by</param>
        public ModPropertyComparer(PropertyDescriptor property, ListSortDirection direction)
        {
            this.propertyDescriptor = property;
            Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
            this.comparer = (IComparer) comparerForPropertyType.InvokeMember("Default", BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, null, null, null, CultureInfo.CurrentCulture);
            this.SetListSortDirection(direction);
        }

        #region IComparer<T> Members
        /// <summary>
        /// Compares both IMod instances with the configured sorting options
        /// </summary>
        /// <param name="x">The first IMod</param>
        /// <param name="y">The second IMod</param>
        /// <returns>An integer defining the first mod's position in relation to the second's</returns>
        public int Compare(T x, T y)
        {
            return this.reverse * this.comparer.Compare(this.propertyDescriptor.GetValue(x), this.propertyDescriptor.GetValue(y));
        }
        #endregion

        /// <summary>
        /// Sets the direction and property descriptor in one method
        /// </summary>
        /// <param name="descriptor">The PropertyDescriptor to sort by</param>
        /// <param name="direction">The ListSortDirection to sort b</param>
        public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
        {
            this.SetPropertyDescriptor(descriptor);
            this.SetListSortDirection(direction);
        }
        
        /// <summary>
        /// Sets the property descriptor to the given value
        /// </summary>
        /// <param name="descriptor">The PropertyDescriptor to sort by</param>
        private void SetPropertyDescriptor(PropertyDescriptor descriptor)
        {
            this.propertyDescriptor = descriptor;
        }

        /// <summary>
        /// Sets the direction to sort by
        /// </summary>
        /// <param name="direction">The ListSortDirection to sort by</param>
        private void SetListSortDirection(ListSortDirection direction)
        {
            this.reverse = direction == ListSortDirection.Ascending ? 1 : -1;
        }
    }
}
